using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;

namespace AliCMS.SystemModule.Bll
{
    public partial class Module : ObjectBase, IModule
    {
        public partial class Object : ObjectBase, SystemModule.Module.IObject
        {
            public class Operation : ObjectBase, SystemModule.Module.Object.IOperation
            {
				public Operation(int instanceID, string lang, bool checkRight, string database)
					: base(instanceID, lang, checkRight)
				{
				}

				public override object ExecuteService(HttpContext context)
				{
                    object result = null;

                    string operation = context.Request.QueryString["Operation"];
                    if (operation == "Add")
                    {
                        string ns = context.Request.QueryString["Namespace"];
                        int objectID = Convert.ToInt32(context.Request.QueryString["ObjectID"]);

                        Dictionary<string, object> item = new Dictionary<string, object>();
                        string value = null;
                        value = context.Request.Form["ID"];
                        if (value != null) item[Alias.Module.Object.Operation.ID] = value;
                        value = context.Request.Form["Name"];
                        if (value != null) item[Alias.Module.Object.Operation.Name] = value;
                        value = context.Request.Form["Label"];
                        if (value != null) item[Alias.Module.Object.Operation.Label + Lang] = value;
						value = context.Request.Form["Memo"];
                        if (value != null) item[Alias.Module.Object.Operation.Memo] = value;

                        result = Add(ns, objectID, item);
                    }
                    else if (operation == "Modify")
                    {
                        string ns = context.Request.QueryString["Namespace"];
                        int objectID = Convert.ToInt32(context.Request.QueryString["ObjectID"]);
                        int id = Convert.ToInt32(context.Request.QueryString["ID"]);

                        Dictionary<string, object> changes = new Dictionary<string, object>();
                        string value = null;
                        value = context.Request.Form["Name"];
                        if (value != null) changes[Alias.Module.Object.Operation.Name] = value;
                        value = context.Request.Form["Label"];
                        if (value != null) changes[Alias.Module.Object.Operation.Label + Lang] = value;
						value = context.Request.Form["Memo"];
						if (value != null) changes[Alias.Module.Object.Operation.Memo] = value;

                        Modify(ns, objectID, id, changes);
                    }
                    else if (operation == "Delete")
                    {
                        string ns = context.Request.QueryString["Namespace"];
                        int objectID = Convert.ToInt32(context.Request.QueryString["ObjectID"]);
                        int id = Convert.ToInt32(context.Request.QueryString["ID"]);

                        Delete(ns, objectID, id);
                    }
                    else if (operation == "List")
                    {
                        result = HandleCommonList(context);
                    }
                    else
                    {
                        throw new Exception("lang_header_param");
                    }

                    return result;
                }

				public Dictionary<string, object> Get(string ns, int objectID, int id)
                {
                    if (CheckRight)
                    {
                        ValidateRight("Get", Guid.Empty);
                    }

                    string path = Manager.MapPath(Manager.GetModulePath(ns) + "module.config");
                    if (!File.Exists(path))
                    {
                        Exception exp = new Exception("lang_module_not_exist");
                        exp.Data.Add(1, ns);
                        throw exp;
                    }

                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.Load(path);
                    XmlNode node = xmlDoc.SelectSingleNode("//Objects//Object[InnerID=" + objectID + "]/Operations/Operation[position()=" + id + "]");
                    if (node == null)
                    {
                        Exception exp = new Exception("lang_operation_not_exist");
                        exp.Data.Add(1, ns);
                        exp.Data.Add(2, objectID);
                        exp.Data.Add(3, id);
                        throw exp;
                    }

                    Dictionary<string, object> result = new Dictionary<string, object>();
                    result[Alias.Module.Object.Operation.ID] = node.SelectSingleNode("ID").InnerText;
                    result[Alias.Module.Object.Operation.ObjectID] = node.ParentNode.ParentNode.SelectSingleNode("ID").InnerText;

                    XmlNode nameNode = node.SelectSingleNode("Name");
                    result[Alias.Module.Object.Operation.Name] = nameNode.InnerText;
                    if (nameNode.Attributes[Lang] != null)
                        result[Alias.Module.Object.Operation.Label] = nameNode.Attributes[Lang].Value;
                    else
                        result[Alias.Module.Object.Operation.Label] = nameNode.InnerText;

					XmlNode memoNode = node.SelectSingleNode("Memo");
					if (memoNode != null)
						result[Alias.Module.Object.Operation.Memo] = memoNode.InnerText;
					else
						result[Alias.Module.Object.Operation.Memo] = "";

                    return result;
                }
				public Guid Add(string ns, int objectID, Dictionary<string, object> item)
                {
                    if (CheckRight)
                    {
                        ValidateRight("Add", Guid.Empty);
                    }

                    string path = Manager.MapPath(Manager.GetModulePath(ns) + "module.config");
                    if (!File.Exists(path))
                    {
                        Exception exp = new Exception("lang_module_not_exist");
                        exp.Data.Add(1, ns);
                        throw exp;
                    }

                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.Load(path);
                    XmlNode objectNode = xmlDoc.SelectSingleNode("//Objects//Object[InnerID=" + objectID + "]");
                    if (objectNode == null)
                    {
                        Exception exp = new Exception("lang_object_not_exist");
                        exp.Data.Add(1, ns);
                        exp.Data.Add(2, objectID);
                        throw exp;
                    }

                    XmlNode parentNode = objectNode.SelectSingleNode("Operations");
                    if (parentNode == null)
                    {
                        parentNode = xmlDoc.CreateElement("Operations");
                        objectNode.AppendChild(parentNode);
                    }

                    XmlNode operationNode = xmlDoc.CreateElement("Operation");
                    parentNode.AppendChild(operationNode);

                    XmlNode node = null;

                    node = xmlDoc.CreateElement("ID");
                    operationNode.AppendChild(node);
                    if (item.ContainsKey(Alias.Module.Object.ID) && !String.IsNullOrEmpty(Convert.ToString(item[Alias.Module.Object.Operation.ID])))
                        node.InnerText = item[Alias.Module.Object.Operation.ID].ToString();
                    else
                        node.InnerText = Guid.NewGuid().ToString();
                    Guid guid = new Guid(node.InnerText);

                    node = xmlDoc.CreateElement("Name");
                    operationNode.AppendChild(node);
                    if (item.ContainsKey(Alias.Module.Object.Operation.Name))
                        node.InnerText = item[Alias.Module.Object.Operation.Name].ToString();

                    XmlAttribute attr = xmlDoc.CreateAttribute(Lang);
                    attr.Value = item[Alias.Module.Object.Operation.Label + Lang].ToString();
                    node.Attributes.Append(attr);

					node = xmlDoc.CreateElement("Memo");
					operationNode.AppendChild(node);
					if (item.ContainsKey(Alias.Module.Object.Operation.Memo))
						node.InnerText = item[Alias.Module.Object.Operation.Memo].ToString();

                    xmlDoc.Save(path);

                    return guid;
                }
				public void Modify(string ns, int objectID, int id, Dictionary<string, object> changes)
                {
                    if (CheckRight)
                    {
                        ValidateRight("Modify", Guid.Empty);
                    }

                    string path = Manager.MapPath(Manager.GetModulePath(ns) + "module.config");
                    if (!File.Exists(path))
                    {
                        Exception exp = new Exception("lang_module_not_exist");
                        exp.Data.Add(1, ns);
                        throw exp;
                    }

                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.Load(path);
                    XmlNode operationNode = xmlDoc.SelectSingleNode("//Objects//Object[InnerID=" + objectID + "]/Operations/Operation[position()=" + id + "]");
                    if (operationNode == null)
                    {
                        Exception exp = new Exception("lang_operation_not_exist");
                        exp.Data.Add(1, ns);
                        exp.Data.Add(2, objectID);
                        exp.Data.Add(3, id);
                        throw exp;
                    }

                    XmlNode node = null;

                    if (changes.ContainsKey(Alias.Module.Object.Operation.Name))
                    {
                        node = operationNode.SelectSingleNode("Name");
                        if (node == null)
                        {
                            node = xmlDoc.CreateElement("Name");
                            operationNode.AppendChild(node);
                        }
                        node.InnerText = changes[Alias.Module.Object.Operation.Name].ToString();
                    }

                    if (changes.ContainsKey(Alias.Module.Object.Operation.Label + Lang))
                    {
                        XmlAttribute attr = node.Attributes[Lang];
                        if (attr == null)
                        {
                            attr = xmlDoc.CreateAttribute(Lang);
                            node.Attributes.Append(attr);
                        }
                        attr.Value = changes[Alias.Module.Object.Operation.Label + Lang].ToString();
                    }

					if (changes.ContainsKey(Alias.Module.Object.Operation.Memo))
					{
						node = operationNode.SelectSingleNode("Memo");
						if (node == null)
						{
							node = xmlDoc.CreateElement("Memo");
							operationNode.AppendChild(node);
						}
						node.InnerText = changes[Alias.Module.Object.Operation.Memo].ToString();
					}

                    xmlDoc.Save(path);
                }
				public void Delete(string ns, int objectID, int id)
                {
                    if (CheckRight)
                    {
                        ValidateRight("Delete", Guid.Empty);
                    }

                    string path = Manager.MapPath(Manager.GetModulePath(ns) + "module.config");
                    if (!File.Exists(path))
                    {
                        Exception exp = new Exception("lang_module_not_exist");
                        exp.Data.Add(1, ns);
                        throw exp;
                    }

                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.Load(path);
                    XmlNode node = xmlDoc.SelectSingleNode("//Objects//Object[InnerID=" + objectID + "]/Operations/Operation[position()=" + id + "]");
                    if (node == null)
                    {
                        Exception exp = new Exception("lang_operation_not_exist");
                        exp.Data.Add(1, ns);
                        exp.Data.Add(2, objectID);
                        exp.Data.Add(3, id);
                        throw exp;
                    }

                    node.ParentNode.RemoveChild(node);

                    xmlDoc.Save(path);
                }
				public DataTable List(int page, int pageSize, Dictionary<string, object> condition, Dictionary<string, string> sort)
				{
					return _List(page, pageSize, condition, sort);
				}
				protected override DataTable _List(int page, int pageSize, Dictionary<string, object> condition, Dictionary<string, string> sort)
                {
                    if (CheckRight)
                    {
                        ValidateRight("List", Guid.Empty);
                    }

                    string root = Manager.MapPath(Manager.GetModulePath(null));
                    if (!Directory.Exists(root))
                        throw new Exception("lang_module_directory_not_exist");

                    DataTable result = new DataTable();
                    result.Columns.Add(Alias.Module.Object.Operation.ID, typeof(Guid));
                    result.Columns.Add(Alias.Module.Object.Operation.InnerID, typeof(int));
                    result.Columns.Add(Alias.Module.Object.Operation.ObjectID, typeof(Guid));
                    result.Columns.Add(Alias.Module.Object.Operation.Name, typeof(string));
                    result.Columns.Add(Alias.Module.Object.Operation.Label, typeof(string));
                    result.Columns.Add(Alias.Module.Object.Operation.Memo, typeof(string));

                    int curIndex = 0, rowIndex = 0;
                    int startIndex = (page - 1) * pageSize;

                    XmlDocument xmlDoc = new XmlDocument();

                    string[] modules = Directory.GetFiles(root, "module.config", SearchOption.AllDirectories);
                    foreach (string file in modules)
                    {
                        string ns = Path.GetDirectoryName(file).Substring(root.Length);
                        if (condition != null && condition.ContainsKey(Alias.Module.Object.Operation.Namespace) && condition[Alias.Module.Object.Operation.Namespace].ToString() != ns)
                            continue;

                        xmlDoc.Load(file);

                        string objectCondition = null;
                        if (condition != null)
                        {
                            if (condition.ContainsKey(Alias.Module.Object.Operation.ObjectInnerID))
                                objectCondition = "InnerID='" + condition[Alias.Module.Object.Operation.ObjectInnerID] + "'";

                            if (condition.ContainsKey(Alias.Module.Object.Operation.ObjectID))
                            {
                                if (objectCondition != null)
                                    objectCondition += " and ";

                                objectCondition += "contains(translate(ID, 'abcdef', 'ABCDEF'), '" + condition[Alias.Module.Object.Operation.ObjectID].ToString().Trim(new char[] { '{', '}' }).ToUpper() + "')";
                            }

                            if (objectCondition != null)
                                objectCondition = "[" + objectCondition + "]";
                        }

                        XmlNodeList nodeList = xmlDoc.SelectNodes("//Objects//Object" + objectCondition + "/Operations/Operation");
                        int innerID = 0;
                        foreach (XmlNode node in nodeList)
                        {
                            innerID++;

                            Guid id = new Guid(node.SelectSingleNode("ID").InnerText);

                            if (condition != null)
                            {
                                if (condition.ContainsKey(Alias.Module.Object.Operation.InnerID) && Convert.ToInt32(condition[Alias.Module.Object.Operation.InnerID]) == innerID)
                                    continue;

                                if (condition.ContainsKey(Alias.Module.Object.Operation.ID) && !Guid.Equals(condition[Alias.Module.Object.Operation.ID], id))
                                    continue;
                            }

                            if (pageSize != -1)
                            {
                                if (curIndex < startIndex)
                                {
                                    curIndex++;
                                    continue;
                                }

                                if (rowIndex == pageSize)
                                    goto Exit;
                            }

                            DataRow row = result.NewRow();
                            row[Alias.Module.Object.Operation.ID] = id;
                            row[Alias.Module.Object.Operation.InnerID] = innerID;
                            row[Alias.Module.Object.Operation.ObjectID] = node.ParentNode.ParentNode.SelectSingleNode("ID").InnerText;

                            XmlNode nameNode = node.SelectSingleNode("Name");
                            row[Alias.Module.Object.Operation.Name] = nameNode.InnerText;
                            if (nameNode.Attributes[Lang] != null)
                                row[Alias.Module.Object.Operation.Label] = nameNode.Attributes[Lang].Value;
                            else
                                row[Alias.Module.Object.Operation.Label] = nameNode.InnerText;

							XmlNode memoNode = node.SelectSingleNode("Memo");
							if (memoNode != null)
								row[Alias.Module.Object.Operation.Memo] = memoNode.InnerText;
							
							result.Rows.Add(row);

                            rowIndex++;
                        }
                    }

                Exit:
                    return result;
                }
				public DataTable List(int page, int pageSize, string condition, string sort)
                {
                    Dictionary<string, object> newCondition = null;
                    if (!String.IsNullOrEmpty(condition))
                    {
                        newCondition = new Dictionary<string, object>();
                        string[] conditions = condition.Split(new string[] { " and ", " AND " }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string c in conditions)
                        {
                            string[] pair = c.Split('=');
                            newCondition[pair[0]] = pair[1];
                        }
                    }

                    return List(page, pageSize, newCondition, (Dictionary<string, string>)null);
                }
				public int GetRecordCount(Dictionary<string, object> condition)
                {
                    DataTable result = _List(-1, -1, condition, null);
                    return result.Rows.Count;
                }
				public int GetRecordCount(string condition)
                {
                    Dictionary<string, object> newCondition = null;
                    if (!String.IsNullOrEmpty(condition))
                    {
                        newCondition = new Dictionary<string, object>();
                        string[] conditions = condition.Split(new string[] { " and ", " AND " }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string c in conditions)
                        {
                            string[] pair = c.Split('=');
                            newCondition[pair[0]] = pair[1];
                        }
                    }

                    return GetRecordCount(newCondition);
                }
            }
        }
    }
}
